package model.scriptrunner

import groovy.transform.CompileStatic
import model.agent.AgentVariable
import model.agent.AgentVariableInterface
import model.agent.question.QuestionInterface
import model.humanbody.BodyInterface

/**
 * 用于执行relation脚本。
 * 执行结果会先储存到缓存中，最后一次性写入到HumanBody中
 * @author lee
 *
 */
@CompileStatic
class ScriptRunner {

	QuestionableInterface questioner

	float esixtThreshold = 10

	List<Float> levelThreshold = [5f, 10f, 15f]

	private GroovyShell shell

	private Binding binding

	private BodyInterface body;

	String scriptPath = ""
	String script = ""

	private HashMap<String,Integer> valueBuffer = [:]

	private ArrayList<String> checkBuffer = []
	
	private int ticks = 0

//	private  globalVars = [:]

	private void initScripts(){
		script = ""
		new File(scriptPath).eachFile{ File f -> 

			if(f.absolutePath[-7..-1] == ".groovy"){

				if(f.name=="GlobalVars.groovy"){
					f.text.eachLine {String line ->
						def parts = line.split("=")
						def var = new AgentVariable(parts[0])
						body.addVariable(var)
						if(parts.size() == 2){
							var.value = parts[2].toInteger()
						}
						//def (var,value) = line.split("=")
						//body.addVariable(new AgentVariable(name:var,value:value))
						
					}
				}else{
					script += f.text +"\n"
				}
			}
		}
	}

	private void setValue(String name, int value){
		valueBuffer[name] = value
	}

	/**
	 * 重新读取脚本文件，并清除指令缓存
	 * @return
	 */
	def reload(){
		initScripts()
		valueBuffer.clear()
	}

	/**
	 * 闭包，用于向外界提问，接收答案，然后设置变量值
	 * 唯一参数是一个变量名的字符串
	 * @return 返回level级别，0,1,2,3,4
	 */
	def confirm = { String varName ->

		AgentVariableInterface var = body.searchVariable(varName)
		QuestionInterface questions

		int level = 0

		if(var!=null){

			// 回答确定性问题
			questions = var.existentialQuestions

			// 曾经提问过的问题，不用再问一次(变量保留原值)
			//if(questions.lastResult >= 0 ) return;

			List<String> ans = questioner.ask(questions.toString())

			// 返回null表示暂时不做回答
			if(ans != null){
				//println questions.answer(ans)
				// 答案>=阈值
				if(questions.answer(ans) >= esixtThreshold) {

					// 回答程度性问题
					questions = var.levelQuestions

					float result = questions.answer(ans)

					// 设置三个级别
					if(result <= levelThreshold[0]){
						level = 1
					}else if(result <= levelThreshold[1]){
						level = 2
					}else{
						level = 3
					}
					setValue(var.name, level)
					//println scriptBuffer
				}
			}

		}
		return level
	}

	def askYesNo = { String question ->
		def res = questioner.askYesNo(question)
		return res
	}

//	def runOnce = { String var, Closure cmds ->
//		if(!body.searchVariable(var).isChecked()){
//
//			//body.searchVariable(var).check()
//			checkBuffer.add(var)
//			this.with{ cmds() }
//		}
//	}

	def askSingle = {String varName, question, options ->
//		shell.evaluate("def 头痛部位 = 1")
//		def value = shell.evaluate("头痛部位")
//		println value

	}
	
	def rand =  {
		Math.random() * 100
	}
	
	def check = { String name, Closure cmds ->
		
		def var = body.searchVariable(name)

		if(var.timestamp == ticks - 1){

			this.with{ cmds() }
		}
		
	}

	//==========================================================


	def ScriptRunner(BodyInterface body,String scriptPath,QuestionableInterface questioner ){
		this.body = body
		this.scriptPath = scriptPath

		this.questioner = questioner

		binding = new Binding();
		shell = new GroovyShell(binding);

		//访问mainObject的属性
		binding.setVariable("scriptRunner", this)
		//binding.setVariable("comfirm",confirm)
		//binding.setVariable("askYesNo", askYesNo)
		//binding.setVariable("runOnce",runOnce)
		//binding.setVariable("askSingle",askSingle)
		binding.setVariable("rand",rand)

		initScripts()
	}

	/**
	 * 模型运行一步
	 */
	@CompileStatic
	def run(){
		ticks ++
		shell.evaluate("scriptRunner.with{$script}")
		flush()
	}

//	def run(String tmpScript){
//		ticks ++
//		shell.evaluate(tmpScript)
//		flush()
//	}

	/**
	 * 脚本用setter，结果值先不写入body，留在scriptBuffer中，等待flush
	 * @param name
	 * @param value
	 */
	def propertyMissing(String name, int value) {
		valueBuffer[name] = value
	}

	/**
	 * 脚本用getter，取值的时候可以直接返回其值
	 * @param name 属性的名字
	 * @return 属性值
	 */
	def propertyMissing(String name) { body.getCondition(name)}

	/**
	 * 将scriptBuffer中的变量值一次性写入body中
	 * @return
	 */
	@CompileStatic
	private flush(){

		valueBuffer.each{String key, int value ->
			
			AgentVariableInterface var = body.searchVariable(key)
			var.value = value
			var.setTimestamp(ticks)
			
		}
		valueBuffer.clear()

	}
	
	/**
	 * 计数器ticks归零
	 */
	public void resetTicks(){
		ticks = 0 
	}


}
